package com.solome.net;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.Random;

/**
 * Math 类包含用于执行基本数学运算的方法，如初等指数、对数、平方根和三角函数。
 * 
 */
public class KMath {
	/** 正弦表 */
	private static final short[] SINES = { 0, 4, 8, 13, 17, 22, 26, 31, 35, 40,
			44, 48, 53, 57, 61, 66, 70, 74, 79, 83, 87, 91, 95, 100, 104, 108,
			112, 116, 120, 124, 127, 131, 135, 139, 143, 146, 150, 154, 157,
			161, 164, 167, 171, 174, 177, 181, 184, 187, 190, 193, 196, 198,
			201, 204, 207, 209, 212, 214, 217, 219, 221, 223, 226, 228, 230,
			232, 233, 235, 237, 238, 240, 242, 243, 244, 246, 247, 248, 249,
			250, 251, 252, 252, 253, 254, 254, 255, 255, 255, 256, 256, 256 };

	/**
	 * 求某个角度的正弦值
	 * 
	 * @param angle
	 *            计算角度
	 * @return 正弦值
	 */
	public static final int sin(int angle) {
		angle %= 360;
		if (angle < 0) {
			angle = 360 + angle;
		}
		if (angle <= 90) {
			return SINES[angle];
		} else if (angle <= 180) {
			return SINES[180 - angle];
		} else if (angle <= 270) {
			return -SINES[angle - 180];
		} else {
			return -SINES[360 - angle];
		}
	}

	/**
	 * 求某个角度的余弦值
	 * 
	 * @param angle
	 *            计算角度
	 * @return 余弦值
	 */
	public static final int cos(int angle) {
		return sin(angle + 90);
	}

	/**
	 * 计算某个Int数值内包含0x1的个数
	 * 
	 * @param x
	 *            来源数值
	 * @return 包含0x1的个数
	 */
	public static final int calcbtis(int x) {
		int result = 0;
		if (x > 0) {
			x = x - ((x >> 1) & 0x55555555);
			x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
			x = (x + (x >> 4)) & 0x0F0F0F0F;
			x = x + (x >> 8);
			x = x + (x >> 16);
			result = x & 0x0000003F;
		}
		return result;
	}

	/**
	 * 求指数的Power算法
	 * 
	 * @param v
	 *            基数
	 * @param exp
	 *            幂数
	 * @return 计算结果
	 */
	public static final int pow(int v, int exp) {
		int t = exp >> 1;
		int m = exp - (exp >> 1 << 1);
		int r = v;
		for (int i = -1; ++i < t;) {
			r *= v;
		}
		return m == 0 ? r : r * v;
	}

	/**
	 * 求某数的开平方
	 * 
	 * @param strSrc
	 * @return 开方值
	 */
	public static final int sqrt(int value) {
		int sqrt = 0;
		for (int k = 0x100000; k != 0; k >>= 2) {
			int tmp = sqrt + k;
			sqrt >>= 1;
			if (tmp <= value) {
				value -= tmp;
				sqrt += k;
			}
		}
		return sqrt;
	}

	/**
	 * CRC特征表
	 */
	private static int[] CRC_TABLE;

	/**
	 * 初始化CRC特征表
	 */
	private static final void createCrcTable() {
		CRC_TABLE = new int[256];
		int c;
		int n, k;
		for (n = 0; n < 256; n++) {
			c = n;
			for (k = 0; k < 8; k++) {
				if ((c & 1) == 1) {
					c = 0xEDB88320 ^ (c >> 1);
				} else {
					c = c >> 1;
				}
			}
			CRC_TABLE[n] = c;
		}
	}

	/**
	 * @param buf
	 * @param start
	 * @param end
	 * @return
	 */
	public static long getValue(byte[] buf, int start, int end) {
		if (buf == null) {
			CRC_TABLE = null;
			return 0;
		}
		if (CRC_TABLE == null) {
			createCrcTable();
		}
		long c = 0xFFFFFFFFL;
		for (int i = start; i < end; i++) {
			c = (CRC_TABLE[(int) ((c ^ buf[i]) & 0xFF)] ^ (c >> 8));
		}
		return c ^ 0xFFFFFFFFL;
	}

	/**
	 * 把字符串转成数字
	 * 
	 * @param str
	 * @param begin
	 * @param end
	 * @return
	 */
	public static int getInt(String str, int begin, int end) {
		try {
			return Integer.parseInt(str.substring(begin, end));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return 0;
	}

	/**
	 * @param x1
	 * @param y1
	 * @param x2
	 * @param y2
	 * @return
	 */
	public static final int getDistance(int x1, int y1, int x2, int y2) {
		return KMath.sqrt(((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
	}

	/**
	 * @param x1
	 * @param y1
	 * @param x2
	 * @param y2
	 * @return
	 */
	public static final int getXYMaxDistance(int x1, int y1, int x2, int y2) {

		return Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2));
	}

	/**
	 * 计算CRC32的值，CRC查找将会自动被创建。 当传入的字节数组为NULL的时候，引擎自动释放查找表。
	 * 
	 * @param buf
	 *            进行数据校验计算的数据来源，如果此值为空，则表示提交引擎释放查找表
	 * @param start
	 *            起始点
	 * @param end
	 *            结束点
	 * @return CRC值
	 */
	public static int getIntValue(byte[] buf, int start, int end) {
		return (int) getValue(buf, start, end);
	}

	/**
	 * 从流里读取一个UTF字符串
	 * 
	 * @param dis
	 * @return
	 * @throws IOException
	 */
	public static String read(DataInputStream dis) throws IOException {
		short length = dis.readShort();
		byte[] buf = new byte[length];
		dis.read(buf);
		String str = new String(buf, "UTF-8");
		return str;
	}

	/**
	 * 从字节数组里读取一个UTF8字符串
	 * 
	 * @param in
	 *            来源数组
	 * @param offset
	 *            偏移量
	 * @param length
	 *            读取长度
	 * @return 读出的UTF8字符串
	 */
	public static final String decode(byte in[], int offset, int length) {
		StringBuffer buff = new StringBuffer();
		int max = offset + length;
		for (int i = offset; i < max; i++) {
			char c = 0;
			if ((in[i] & 0x80) == 0) {
				c = (char) in[i];
			} else if ((in[i] & 0xe0) == 0xc0) {// 11100000
				c |= ((in[i++] & 0x1f) << 6); // 00011111
				c |= ((in[i] & 0x3f) << 0); // 00111111
			} else if ((in[i] & 0xf0) == 0xe0) {// 11110000
				c |= ((in[i++] & 0x0f) << 12); // 00001111
				c |= ((in[i++] & 0x3f) << 6); // 00111111
				c |= ((in[i] & 0x3f) << 0); // 00111111
			} else if ((in[i] & 0xf8) == 0xf0) {// 11111000
				c |= ((in[i++] & 0x07) << 18); // 00000111 (move 18, not 16?)
				c |= ((in[i++] & 0x3f) << 12); // 00111111
				c |= ((in[i++] & 0x3f) << 6); // 00111111
				c |= ((in[i] & 0x3f) << 0); // 00111111
			} else {
				c = '?';
			}
			buff.append(c);
		}
		return buff.toString();
	}

	/**
	 * 从字节数组里读取一个UTF8字符串
	 * 
	 * @param in
	 *            来源数组
	 * @return 读出的UTF8字符串
	 */
	public static final String decode(byte[] in) {
		return decode(in, 0, in.length);
	}

	/**
	 * UTF8编码的自定义实现
	 * 
	 * @param strSrc
	 *            源字符串
	 * @return 转换后的字节数组
	 */
	public static final byte[] encode(String value) {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		try {
			int strlen = value.length();
			for (int i = 0; i < strlen; i++) {
				char t = value.charAt(i);
				int c = 0;
				c |= (t & 0xffff);
				if (c >= 0 && c < 0x80) {
					bos.write((byte) (c & 0xff));
				} else if (c > 0x7f && c < 0x800) {
					bos.write((byte) (((c >>> 6) & 0x1f) | 0xc0));
					bos.write((byte) (((c >>> 0) & 0x3f) | 0x80));
				} else if (c > 0x7ff && c < 0x10000) {
					bos.write((byte) (((c >>> 12) & 0x0f) | 0xe0));
					bos.write((byte) (((c >>> 6) & 0x3f) | 0x80));
					bos.write((byte) (((c >>> 0) & 0x3f) | 0x80));
				} else if (c > 0x00ffff && c < 0xfffff) {
					bos.write((byte) (((c >>> 18) & 0x07) | 0xf0));
					bos.write((byte) (((c >>> 12) & 0x3f) | 0x80));
					bos.write((byte) (((c >>> 6) & 0x3f) | 0x80));
					bos.write((byte) (((c >>> 0) & 0x3f) | 0x80));
				}
			}
			bos.flush();
			return bos.toByteArray();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (bos != null) {
					bos.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * 随机数种子
	 */
	private static final Random RANDOM = new Random();

	/**
	 * 获取指定范围内的随机整数。
	 * 
	 * @param min
	 *            随机数范围的下限
	 * @param max
	 *            随机数范围的上限
	 * @return 指定范围内的一个整数
	 */
	public static final int getRandom(int min, int max) {
		return min + Math.abs(RANDOM.nextInt())
				/ (Integer.MAX_VALUE / (max - min + 1) + 1);
	}

}
